#include "network_info.h"

#define PORT 12345
#define BUFFER_SIZE 1024

// 线程函数，用于监听TCP连接并解析指令
void *tcp_listener_thread(void *arg) {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    fd_set readfds;
    struct timeval timeout;
    int *uart_fd = (int*)(arg);

    // 创建socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 绑定地址
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    printf("Listening on port %d...\n", PORT);

    while (1) {
        // 设置select的参数
        FD_ZERO(&readfds);
        FD_SET(server_fd, &readfds);

        // 设置超时时间
        timeout.tv_sec = 2; // 5秒超时
        timeout.tv_usec = 0;

        // 等待连接
        int activity = select(server_fd + 1, &readfds, NULL, NULL, &timeout);

        if (activity < 0) {
            perror("select error");
            exit(EXIT_FAILURE);
        }

        if (activity == 0) {
            // 超时，没有数据
            // printf("No data within the timeout period.\n");
            continue;
        }

        if (FD_ISSET(server_fd, &readfds)) {
            if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
            }

            // 读取数据
            while (1) {
                int read_size = read(new_socket, buffer, BUFFER_SIZE);
                if (read_size <= 0) {
                    break; // 连接关闭或读取结束
                }
                buffer[read_size] = '\0'; // 确保字符串正确终止
                printf("Received: %s\n", buffer);

                // 这里可以添加解析指令的代码
                int fd = *uart_fd;
                char buf[8] = {0xaa, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 

                if(buffer[0] == 0x88)
                {
                    if(buffer[1] <= IRON_RED_PSEUDO_COLOR && buffer[1] >= 0)
                    {
                        buf[2] = buffer[1];
                        buf[7] =  buf[1] + buf[2] + buf[3] + buf[4]  + buf[5] + buf[6];
                        serial_write(fd, buf, sizeof(buf));
                    }
                    else
                    {
                        fprintf(stderr,"Unsupport cmd!\n");
                    }
                }
                // 清空缓冲区
                memset(buffer, 0, sizeof(buffer));
            }

            close(new_socket);
        }
    }

    close(server_fd);
    return NULL;
}


static int check_file(const char* path, int type)
{
    if(!path)
    {
        fprintf(stderr,"path is null!\n");
        return -1;
    }
    struct stat info;

    if(type == TYPE_DIR)
    {
        int status = stat(path, &info);
        if (status != 0) 
        {
            if (errno == ENOENT) 
            {
                if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 
                {
                    fprintf(stderr,"Dir '%s' created\n", path);
                } 
                else 
                {
                    perror("Created Dir failed.");
                    return -1;
                }
            } 
            else 
            {
                perror("Check Dir Failed.");
                return -1;
            }
        }
    }
    else if(type == TYPE_FILE)
    {
        int  status = stat(path, &info);
        if (status != 0) 
        {
            if (errno == ENOENT) 
            {
                FILE* fp = fopen(path, "w+");
                if (fp) 
                {
                    fprintf(stderr,"File '%s' creates success.\n", path);
                    fclose(fp);
                } else 
                {
                    perror("Create File failed.");
                    return -1;
                }
            } 
            else 
            {
                perror("Check file failed.");
                return -1;
            }
        }
    }
    else
    {
        fprintf(stderr,"Type dismatch.\n");
        return -1;
    }
    return 0;
}

int create_empty_ini_file()
{
    int ret = check_file(CONFIG_DIR_NAME, TYPE_DIR);
    if(0 > ret){
        fprintf(stderr,"check_dir file!\n");
        return -1;
    }
    ret = check_file(CONFIG_INI_NAME, TYPE_FILE);
    if(0 > ret){
        fprintf(stderr,"check_config_ini file!\n");
        return -1;
    }

    return 0;
}

int write_netinfo_to_ini(void *st, char *filename)
{
    if (!filename || !st) {
        fprintf(stderr, "Invalid argurment\n");
        return -1;
    }

    NetInfo *net_info = (NetInfo *)st;
    void *dictionary;
    FILE *ini_file;
    int ret = -1;

    dictionary = iniparser_load(filename);
    if (!dictionary) {
        fprintf(stderr, "cannot parse file: %s\n", filename);
        return ret;
    }

      /* set section */
    ret = iniparser_set(dictionary, "network", NULL);
    if (ret < 0) {
        fprintf(stderr, "cannot set section in: %s\n", filename);
        ret = -1;
        goto free_dict;
    }

    /* set key/value pair */
    ret = iniparser_set(dictionary, "network:ipv4_addr", net_info->ipv4_addr);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    ret = iniparser_set(dictionary, "network:ipv4_gateway", net_info->ipv4_gateway);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    ret = iniparser_set(dictionary, "network:ipv4_mask", net_info->ipv4_mask);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    ret = iniparser_set(dictionary, "network:dns", net_info->dns);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    ini_file = fopen(filename, "w+");
    if (!ini_file) {
        fprintf(stderr, "iniparser: cannot create example.ini\n");
        goto free_dict;
    }

    iniparser_dump_ini(dictionary, ini_file);
    fclose(ini_file);

free_dict:
    iniparser_freedict(dictionary);
    return ret;
}

int write_chipctrl_to_ini(void *st, char *filename)
{
    if (!filename || !st) {
        fprintf(stderr, "Invalid argurment\n");
        return -1;
    }

    ChipCtrl *chip_ctrl = (ChipCtrl *)st;
    void *dictionary;
    FILE *ini_file;

    dictionary = iniparser_load(filename);
    if (!dictionary) {
        fprintf(stderr, "cannot parse file: %s\n", filename);
        return -1;
    }

      /* set section */
    int ret = iniparser_set(dictionary, "camera_chip_info", NULL);
    if (ret < 0) {
        fprintf(stderr, "cannot set section in: %s\n", filename);
        ret = -1;
        goto free_dict;
    }

    /* set key/value pair */
    char value_str[20];
    snprintf(value_str, sizeof(value_str), "%d", chip_ctrl->pseudo_color);
    ret = iniparser_set(dictionary, "camera_chip_info:pseudo_color", value_str);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    snprintf(value_str, sizeof(value_str), "%d", chip_ctrl->electronic_zoom);
    ret = iniparser_set(dictionary, "camera_chip_info:electronic_zoom", value_str);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    snprintf(value_str, sizeof(value_str), "%d", chip_ctrl->shutter_calibration);
    ret = iniparser_set(dictionary, "camera_chip_info:shutter_calibration", value_str);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    snprintf(value_str, sizeof(value_str), "%d", chip_ctrl->outdoor_mode);
    ret = iniparser_set(dictionary, "camera_chip_info:outdoor_mode", value_str);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    ini_file = fopen(filename, "w+");
    if (!ini_file) {
        fprintf(stderr, "iniparser: cannot create example.ini\n");
        goto free_dict;
    }

    iniparser_dump_ini(dictionary, ini_file);
    fclose(ini_file);

free_dict:
    iniparser_freedict(dictionary);
    return ret;
}

int get_netinfo_from_ini(NetInfo *net_info, char *filename)
{
    if (!filename) {
        fprintf(stderr, "Invalid argurment\n");
        return -1;
    }

    dictionary  *   ini ;
    int             rInt;
    const char*  rSrc;

    fprintf(stderr, "[%04d]:filename->%s\n",__LINE__, filename);
    ini = iniparser_load(filename);
    if (ini==NULL) {
        fprintf(stderr, "cannot parse file: %s\n", filename);
        return -1 ;
    }

    // memset(net_info, 0x0, sizeof(NetInfo));
    rSrc = iniparser_getstring(ini, "network:ipv4_addr", NULL);
    if(rSrc){
        strncpy(net_info->ipv4_addr, rSrc, IP_ADDR_MAX_LENGTH - 1);
        net_info->ipv4_addr[IP_ADDR_MAX_LENGTH - 1] = '\0';
    }
    
    rSrc = iniparser_getstring(ini, "network:ipv4_gateway", NULL);
    if(rSrc){
        strncpy(net_info->ipv4_gateway, rSrc, IP_ADDR_MAX_LENGTH - 1);
        net_info->ipv4_gateway[IP_ADDR_MAX_LENGTH - 1] = "\0";
    }
   
    rSrc = iniparser_getstring(ini, "network:ipv4_mask", NULL);
    if(rSrc){
        strncpy(net_info->ipv4_mask, rSrc, IP_ADDR_MAX_LENGTH - 1);
        net_info->ipv4_mask[IP_ADDR_MAX_LENGTH -1] = "\0";
    }
    
    rSrc = iniparser_getstring(ini, "network:dns", NULL);
    if(rSrc){
        strncpy(net_info->dns, rSrc, IP_ADDR_MAX_LENGTH - 1);
        net_info->dns[IP_ADDR_MAX_LENGTH-1] = "\0";
    }   
    
    iniparser_freedict(ini);
    return 0 ;
}

int get_chipctrl_from_ini(ChipCtrl *chip_ctrl, char *filename)
{
    if (!filename) {
        fprintf(stderr, "Invalid argurment\n");
        return -1;
    }

    dictionary  *   ini ;
    int             rInt;
    // const char*  rSrc;

    fprintf(stderr, "[%04d]:filename->%s\n",__LINE__, filename);
    ini = iniparser_load(filename);
    if (ini==NULL) {
        fprintf(stderr, "cannot parse file: %s\n", filename);
        return -1 ;
    }

    rInt = iniparser_getint(ini, "camera_chip_info:pseudo_color", -1);
    if(rInt >= 0){
        chip_ctrl->pseudo_color = rInt;
    }

    rInt = iniparser_getint(ini, "camera_chip_info:electronic_zoom", -1);
    if(rInt >= 0){
        chip_ctrl->electronic_zoom = rInt;
    }

    rInt = iniparser_getint(ini, "camera_chip_info:shutter_calibration", -1);
    if(rInt >= 0){
        chip_ctrl->shutter_calibration = rInt;
    }

    rInt = iniparser_getint(ini, "camera_chip_info:outdoor_mode", -1);
    if(rInt >= 0){
        chip_ctrl->outdoor_mode = rInt;
    }

    iniparser_freedict(ini);
    return 0 ;
}

int get_rtspurl_from_ini(void *url, char *filename)
{
    if (!filename) {
        fprintf(stderr, "Invalid argurment\n");
        return -1;
    }

    dictionary  *   ini ;
    int             rInt;
    const char*     rSrc;

    fprintf(stderr, "[%04d]:filename->%s\n",__LINE__, filename);
    ini = iniparser_load(filename);
    if (ini==NULL) {
        fprintf(stderr, "cannot parse file: %s\n", filename);
        return -1 ;
    }

    rSrc = iniparser_getstring(ini, "rtsp_url:url", NULL);
    if(NULL == rSrc){
        fprintf(stderr, "[%04d]:rtsp_url:url is NULL\n",__LINE__);
        iniparser_freedict(ini);
        return -1;
    }
    strncpy(url, rSrc, strlen(rSrc));

    fprintf(stdout, "[%04d]:rtsp_url:url is %s\n",__LINE__, url);

    iniparser_freedict(ini);
    return 0 ;
}

int write_rtspurl_to_ini(void *st, char *filename)
{
    if (!filename || !st) {
        fprintf(stderr, "Invalid argurment\n");
        return -1;
    }

    void *dictionary;
    FILE *ini_file;
    const char*     rSrc;
    char ipaddr[16] = {0};

    dictionary = iniparser_load(filename);
    if (!dictionary) {
        fprintf(stderr, "cannot parse file: %s\n", filename);
        return -1;
    }

      /* set section */
    int ret = iniparser_set(dictionary, "rtsp_url", NULL);
    if (ret < 0) {
        fprintf(stderr, "cannot set section in: %s\n", filename);
        ret = -1;
        goto free_dict;
    }

    rSrc = iniparser_getstring(dictionary, "network:ipv4_addr", NULL);
    if(rSrc){
        strncpy(ipaddr, rSrc, IP_ADDR_MAX_LENGTH - 1);
    }

    /* set key/value pair */
    char tmpSRc[1024] = {0};
    snprintf(tmpSRc, sizeof(tmpSRc),"rtsp://%s:554/mainstream", ipaddr);
    ret = iniparser_set(dictionary, "rtsp_url:url", tmpSRc);
    if (ret < 0) {
        fprintf(stderr, "cannot set key/value in: %s\n", filename);
        goto free_dict;
    }

    ini_file = fopen(filename, "w+");
    if (!ini_file) {
        fprintf(stderr, "iniparser: cannot create example.ini\n");
        goto free_dict;
    }

    iniparser_dump_ini(dictionary, ini_file);
    fclose(ini_file);

free_dict:
    iniparser_freedict(dictionary);
    return ret;
}